// SPDX-License-Identifier: GPL-2.0
/*
 * ZONE_DEVICE
 *
 * (C) 2024.03.13 BuddyZhang1 <buddy.zhang@aliyun.com>
 */
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/memremap.h>
#include <linux/mm.h>

static int __init BiscuitOS_init(void)
{
	struct dev_pagemap *pgmap;
	struct resource *res;
	struct range range;
	struct page *page;
	int nr_pages, r;
	void *vaddr;

	res = kzalloc(sizeof(*res), GFP_KERNEL);
	if (!res)
		return -ENOMEM;

	/* cat /proc/iomem */
	res->name = "BiscuitOS Device";
	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;

	/* FAKE RANGE */
	nr_pages = round_up(0x1, PAGES_PER_SECTION);
	range.start = 0x200000000;
	range.end   = range.start + nr_pages * PAGE_SIZE;

	/* INSERT RANGE INTO SYSTEM PHYSICAL ADDRESS BUS */
	r = allocate_resource(&iomem_resource, res,
			nr_pages * PAGE_SIZE, range.start, range.end,
			PAGES_PER_SECTION * PAGE_SIZE,
			NULL, NULL);
	if (r < 0)
		return -ENOMEM; /* IGNORE RECLAIM */

	pgmap = kzalloc(sizeof(*pgmap), GFP_KERNEL);
	if (!pgmap)
		return -ENOMEM; /* IGNORE RECLAIM */

	pgmap->type = MEMORY_DEVICE_GENERIC;
	pgmap->range = (struct range) {
		.start = res->start,
		.end   = res->end,
	};
	pgmap->nr_range = 1;
	pgmap->owner = res;

	/* INSERT PAGE INTO ZONE_DEVICE */
	vaddr = memremap_pages(pgmap, NUMA_NO_NODE);
	if (IS_ERR(vaddr)) {
		printk("Cannot remap memory range\n");
		return -ENOMEM;
	}

	/* USAGE */
	page = virt_to_page(vaddr);
	*(unsigned long *)vaddr = 0x02;

	/* IGNORE RECLAIM */
	return 0;
}

static void __exit BiscuitOS_exit(void) { }

module_init(BiscuitOS_init);
module_exit(BiscuitOS_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("BiscuitOS <buddy.zhang@aliyun.com>");
MODULE_DESCRIPTION("PHYS MEMORY");
